[iOS] UIWindowを追加する
1 はじめに
前回、アラートやキーボードが表示された際の複数のUIWindowについて確認してみましたが、今回は、自分でこのUIWindowを追加して挙動を確認してみました。
今回も、iOS9.3で動作確認しておりますが、他のバージョンで挙動が異なる可能性があることは、予めご了承ください。
2 試験準備
前回のテストプログラムに3つほどボタンを追加し、ここにコードを追加することで試験を進めます。 アプリのUIWindowを列挙するログ出力などは、前回と同じです。
次に、自前で生成するUIWindowを見た目で区別しやすいように、UIWindowを継承したMyWindowを定義しました。そして、ViewControllerの中で、プロパティとしてこのMyWindowを定義し、ここに生成することにします。
@interface MyWindow : UIWindow @end @implementation MyWindow @end @interface ViewController () @property (strong,nonatomic)MyWindow *myWindow; // プロパティとして定義 @end
3 動作確認
(1) UIWindowの生成
上記の①のところに、次のようなコードを追加してMyWidowを生成してみました。
- (IBAction)tapAppendWindow:(id)sender { _myWindow = [MyWindow new];//MyWindowの生成 _myWindow.frame = CGRectMake(100, 100, 200, 200); // 描画範囲 _myWindow.backgroundColor = [UIColor.redColor colorWithAlphaComponent:0.2];//背景色をAlpha値0.2の赤色に設定 }
そして、その時の状況は次のとおりです。
まず、起動時は、普通にUIWindowが一つ存在しています。
[Confirm] Application.windows.count = 1 UIWindow keywindow = 1 hidden=0 lebel=0.000000
そして、MyWindowを生成すると、プロパティに生成しただけなのに、アプリのUIWindowのリストに追加されています。 そう、「アプリのウインドウリストへの追加」のような実装は必要ないようです。
[Confirm] Application.windows.count = 2 UIWindow keywindow = 1 hidden=0 lebel=0.000000 MyWindow keywindow = 0 hidden=1 lebel=0.000000
しかし、見た目上は、生成したMyWindowを確認することは出来ません。
(2) makeKeyAndVisible
次に生成したMyWindowでmakeKeyAndVisibleメソッドを呼び出しました。
- (IBAction)tapAppendWindow:(id)sender { _myWindow = [MyWindow new];//MyWindowの生成 _myWindow.frame = CGRectMake(100, 100, 200, 200); // 描画範囲 _myWindow.backgroundColor = [UIColor.redColor colorWithAlphaComponent:0.2];//背景色をAlpha値0.2の赤色に設定 [_myWindow makeKeyAndVisible]; // <= この行を追加 }
今度は、追加したMyWindowが表示されていることを確認できます。実際に操作してみると、MyWindowの下に隠れているUIコントロールは、操作できません。
ウインドウ状況を確認するとkeywindowが、元のUIWindowから、MyWindowに移動したのが分かります。両方ともレベルが0で同じなので、keywindowであるMyWindowが優先されているのでしょう。
[Confirm] Application.windows.count = 2 UIWindow keywindow = 0 hidden=0 lebel=0.000000 MyWindow keywindow = 1 hidden=0 lebel=0.000000
(3) Viewの追加
UIWindowには、rootViewControllerというプロパティがあり、ここにViewをセットすることで表示させることができます。
ストーリーボードで、View Controlを1つ追加し、Storyboard IDをMyViewControllerとしました。
また、画面の中央にボタンを置き、MyViewControllerクラスを作成してボタンを押したことが分かるようにしました。
MyViewController.h
@implementation MyViewController - (IBAction)tapButton:(id)sender { NSLog(@"tap myView"); }
それでは、また、①のコードに追加して、ウインドウの上にビューを載せてみます。
- (IBAction)tapAppendWindow:(id)sender { _myWindow = [MyWindow new];//MyWindowの生成 _myWindow.frame = CGRectMake(100, 100, 200, 200); // 描画範囲 _myWindow.backgroundColor = [UIColor.redColor colorWithAlphaComponent:0.2];//背景色をAlpha値0.2の赤色に設定 // ストーリーボードを取得 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; // Storyboard IDからビューを生成 UIViewController *myViewController = [storyboard instantiateViewControllerWithIdentifier:@"MyViewController"]; // ルートビューとしてセットする _myWindow.rootViewController = myViewController; [_myWindow makeKeyAndVisible]; }
実行すると、次のようになります。ボタンが押せていることも確認できます。
(4) KeyWindowとWindowLebel
次は、元のUIWindowにKeyWindowを戻してみます。 ②のところに、下記のコードを追加しました。
- (IBAction)tapSetKey:(id)sender { UIWindow *window = [[UIApplication sharedApplication] delegate].window; [window makeKeyAndVisible]; }
実行してみると、ちゃんと、keywindowが戻っています。
[Confirm] Application.windows.count = 2 UIWindow keywindow = 1 hidden=0 lebel=0.000000 MyWindow keywindow = 0 hidden=0 lebel=0.000000
そして、MyWindowは、見えなくなりました。最初の状態と同じです。
ここで、MyWindowのレベルをUIWindowより大きく設定してみます。
_myWindow.windowLevel = 1;
[Confirm] Application.windows.count = 2 UIWindow keywindow = 1 hidden=0 lebel=0.000000 MyWindow keywindow = 0 hidden=0 lebel=1.000000
ちゃんとMyWindow側のボタンも押せることが確認できます。
消去
③に次のコードを書いて実行してみます。単純に参照を消しただけです。
- (IBAction)tapRemoveWindow:(id)sender { _myWindow = nil; }
画面上からMyWindowは消え、ウインドウリストからも居なくなっています。また、自動的にUIWindowにkeywindowが移っていることも確認できました。
[Confirm] Application.windows.count = 1 UIWindow keywindow = 1 hidden=0 lebel=0.000000
4 最後に
今回は、自分でUIWindowを追加することでアプリのUIWindowの動作が、更に見えた気がします。
ここまで来ると、重ね書きを応用して、色々自由に書けそうな気がしてきました。
参考資料
[iOS] 複数のUIWindowの挙動を確認する
UIKit Framework Reference UIWindow Class Reference
iOS開発におけるウィンドウ「UIWindow」の知られざる活用方法とは? #iOS
makeKeyWindow vs makeKeyAndVisible